/**
 * Copyright 2011 Mathieu Magnaudet
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package edu.enac.geoapp.services;

import java.util.List;

import org.geotools.map.MapLayer;

import edu.enac.fileloader.util.Observable;
import edu.enac.fileloader.util.Observer;
import edu.enac.geoapp.gui.component.MapComponent;
import edu.enac.geoapp.gui.component.ViewSelector;
import edu.enac.geoapp.gui.listener.DataScrollListener;
import edu.enac.geoapp.gui.listener.OrientationListener;
import edu.enac.geoapp.gui.listener.RangeListener;
import edu.enac.geoapp.gui.listener.ViewListener;
import edu.enac.geoapp.model.DisplayableView;
import edu.enac.geoapp.model.Orientation;
import edu.enac.geoapp.model.View;

/**
 * Controller between the {@link MapComponent} and the {@link ViewBuilder} 
 * @author mathieu
 * 
 */
public class ViewController implements ViewListener, OrientationListener,
		RangeListener, DataScrollListener, Observer {
	private Orientation orientation;
	private int range;
	private MapComponent mapComponent;
	private ViewBuilder viewBuilder;
	private DisplayableView currentView;
	private View view;
	private ViewSelector viewSelector;
	private List<MapLayer>[] currentData = null;
	private int dateIndex = 0;
	private int nbOfDates = 0;
	private int isoLevelIndex = 0;
	private int nbOfIsoLevels = 0;

	/**
	 * Constructor
	 * @param view the actual view
	 * @param orientation the actual orientation
	 * @param range the actual range 
	 * @param mapComponent the component displaying the views
	 * @param viewSelector the component controlling the change in view
	 */
	public ViewController(View view, Orientation orientation, int range,
			MapComponent mapComponent, ViewSelector viewSelector) {
		this.view = view;
		this.orientation = orientation;
		this.range = range;
		this.mapComponent = mapComponent;
		this.viewSelector = viewSelector;
		viewBuilder = ViewBuilder.getInstance();
		currentView = viewBuilder.getView(view);
		updateMapComponent();
	}

	private void updateMapComponent() {
		for (MapLayer layer : currentView.getBackgroundLayerList()) {
			mapComponent.addLayer(layer);
		}
		if (currentView.hasData()) {
			currentData = currentView.getData();
			nbOfDates = currentView.getNbOfDates();
			dateIndex = 0;
			isoLevelIndex = 0;

			// si les couches de données sont superposables on les ajoute toutes
			// et on empêche la navigation par couches en mettant à 0 le nombre
			// d'isolevels
			if (currentView.isSuperposeLayers()) {
				nbOfIsoLevels = 0;
				for (MapLayer layer : currentData[dateIndex])
					mapComponent.addLayer(layer);
			}
			// sinon on n'ajoute que la première
			else {
				nbOfIsoLevels = currentData[dateIndex].size();
				mapComponent.addLayer(currentData[dateIndex].get(0));
			}
		} else {
			nbOfDates = 0;
			nbOfIsoLevels = 0;
			dateIndex = 0;
			isoLevelIndex = 0;
		}
		updateButtonState();
		mapComponent.resetDefaultEnvelope();
	}

	private void refresh() {
		System.out.println("View: " + view + "\nOrientation: " + orientation
				+ "\nrange: " + range);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.enac.mycomponent.listener.ViewListener#viewChanged(edu.enac.mycomponent
	 * .model.View)
	 */
	@Override
	public void viewChanged(View v) {
		if (!this.view.equals(v)) {
			this.view = v;
			mapComponent.removeAllLayers();
			if (v != View.TEMSI) {
				currentView = viewBuilder.getView(view);
				updateMapComponent();
			} else {
				currentView = null;
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.enac.mycomponent.listener.OrientationListener#orientationChanged(
	 * edu.enac.mycomponent.model.Orientation)
	 */
	@Override
	public void orientationChanged(Orientation orientation) {
		if (!this.orientation.equals(orientation)) {
			this.orientation = orientation;
			refresh();
		}
	}

	@Override
	public void rangeChanged(int newRange) {
		if (this.range != newRange) {
			this.range = newRange;
			refresh();
		}
	}

	@Override
	public void update(Observable o, Object arg) {
		// TODO Auto-generated method stub

	}

	/**
	 * If multiple forecasts in the actual view, change to the next one
	 */
	public void nextDate() {
		mapComponent.removeLayer(currentData[dateIndex].get(isoLevelIndex));
		dateIndex++;
		mapComponent.addLayer(currentData[dateIndex].get(isoLevelIndex));
		updateButtonState();
	}

	/**
	 * If multiple isolevel in the actual view, change to the next one
	 */
	public void nextIsoLevel() {
		if (isoLevelIndex < (nbOfIsoLevels - 1)) {
			mapComponent.removeLayer(currentData[dateIndex].get(isoLevelIndex));
			isoLevelIndex++;
			mapComponent.addLayer(currentData[dateIndex].get(isoLevelIndex));
		}
	}

	/**
	 * If multiple forecasts in the actual view, change to the previous one
	 */
	public void previousDate() {
		mapComponent.removeLayer(currentData[dateIndex].get(isoLevelIndex));
		dateIndex--;
		mapComponent.addLayer(currentData[dateIndex].get(isoLevelIndex));
		updateButtonState();
	}

	/**
	 * If multiple isolevel in the actual view, change to the previous one
	 */
	public void previousIsoLevel() {
		if (isoLevelIndex > 0) {
			mapComponent.removeLayer(currentData[dateIndex].get(isoLevelIndex));
			isoLevelIndex--;
			mapComponent.addLayer(currentData[dateIndex].get(isoLevelIndex));
		}
	}

	private void updateButtonState() {
		viewSelector.setEnabledNextButton(dateIndex < nbOfDates - 1);
		viewSelector.setEnabledPreviousButton(dateIndex > 0);
	}
}
